<script lang="ts" setup>
/**
 * Props
 * @request 获取列表数据接口 --request
 * 必传
 *
 * @params 接口参数 --IObj
 *
 * @height 列表高度
 * 默认100%
 *
 * @mb 列表下边距
 * 默认 0
 *
 * Emits
 * @list 列表数据返回值
 *
 * Expose
 * @getData 获取数据
 *
 * Slot 内容区域
 * Slot="mbbox"
 */
import { getCurrentInstance, nextTick, reactive, ref } from 'vue'
import type { ComponentInternalInstance } from 'vue'
import Image from '@C/Image.vue'
import { hasUnit } from '@U/common'
import { onShow } from '@dcloudio/uni-app'
import { MsgLoading, PMsgLoadingClean } from '@C/Msg'
import type { IFunc, IObj, PropType } from '@/interface'

const { proxy: _this } = getCurrentInstance() as ComponentInternalInstance
const props = defineProps({
  request: {
    type: Function as PropType<IFunc>,
    required: true,
  },
  params: {
    type: Object as PropType<IObj>,
    required: false,
    default: () => ({}),
  },
  ignoreParam: {
    type: Array as PropType<Array<string>>,
    required: false,
    default: () => ([]),
  },
  height: {
    type: String,
    required: false,
    default: '',
  },
  mb: {
    type: String,
    required: false,
    default: '0',
  },
  initIsCall: {
    type: Boolean,
    required: false,
    default: () => true,
  },
})
const emits = defineEmits(['list'])
defineExpose({
  getData,
  clickGetDataFn,
})
onShow(() => {
  // 每一次进入页面初始化数据
  listState.pageNumber = 1
  list.value = []
  if (props.initIsCall) getData()
})

// 滚动区域高度
const scrollHeight = ref(<string>'')

nextTick(() => {
  uni
      .createSelectorQuery()
      .in(_this)
      .select('.prm-auto-list')
      .boundingClientRect((d: IObj) => {
        scrollHeight.value = d.height
      })
      .exec()
})

// 监听滚动操作 --下拉刷新，上滑加载
const scrollState = reactive({
  loading: true, // 是否正在上拉加载
  updating: false, // 是否下拉刷新
})

// 列表状态
const listState = reactive(<IObj>{
  pageNumber: 1,
  pageSize: 10,
  pages: 1,
  total: 0,
})
// 列表数据
const list = ref(<Array<IObj>>[])
// 获取数据
async function getData(page?: IObj) {
  try {
    await MsgLoading()
    const params = props.params
    params?.ignoreParam?.forEach((key: string) => {
      delete params[key]
    })
    const res = await props.request({
      pageNumber: page?.pageNumber ?? listState.pageNumber,
      pageSize: page?.pageSize ?? listState.pageSize,
      ...params,
    })
    if (res?.code === 200) {
      PMsgLoadingClean()
      const { pages, rows, total } = res.data
      listState.total = total
      listState.pages = pages
      list.value = [...list.value, ...rows]
      if (listState.pageNumber > listState.pages || list.value?.length >= listState.total) scrollState.loading = false
      emits('list', list.value, res.data)
    }
  } catch (e) {
    PMsgLoadingClean()
    console.log(e)
  }
}

// 上拉加载
function scrolltolowerFn() {
  if (listState.pageNumber > listState.pages || list.value?.length >= listState.total) {
    scrollState.loading = false
    return
  }
  listState.pageNumber += 1
  scrollState.loading = true
  getData()
}
// 下拉刷新
const pullRefreshFn = async () => {
  list.value = []
  scrollState.updating = true
  listState.pageNumber = 1
  await getData()
  scrollState.updating = false
}
// 手动点击获取数据
function clickGetDataFn() {
  list.value = []
  listState.pageNumber = 1
  getData()
}
</script>

<template>
  <view :style="{height: height ? hasUnit(height) : '100%'}" class="prm-auto-list">
    <scroll-view
      :refresher-enabled="true"
      :refresher-threshold="20"
      :refresher-triggered="scrollState.updating"
      :scroll-x="false"
      :scroll-y="true"
      :show-scrollbar="true"
      :style="{height: `${scrollHeight}px`}"
      @refresherrefresh="pullRefreshFn"
      @scrolltolower="scrolltolowerFn"
    >
      <template v-if="list?.length > 0">
        <slot />
        <div :style="{height: hasUnit(`calc(50rpx + ${hasUnit(mb)})`)}" class="load_tips">
          {{ scrollState.loading ? '正在加载更多~' : '没有更多了~' }}
        </div>
        <slot name="mbbox" />
      </template>
      <div v-else :style="{'margin-top': '200rpx', width: '100%', display: 'flex', 'align-items': 'center', 'flex-direction': 'column'}">
        <Image height="198" name="no_data" oss width="140" />
        <slot name="mbbox" />
      </div>
    </scroll-view>
  </view>
</template>

<style lang="less" scoped>
.load_tips {
  font-size: 24rpx;
  color: rgba(0, 0, 0, 0.45);
  line-height: 36rpx;
  text-align: center;
  margin-top: 20rpx;
}
</style>
